package com.yxw.live_vod_backend_boot.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yxw.live_vod_backend_boot.dto.*;
import com.yxw.live_vod_backend_boot.entity.*;
import com.yxw.live_vod_backend_boot.mapper.DeptMapper;
import com.yxw.live_vod_backend_boot.mapper.RelevancyMapper;
import com.yxw.live_vod_backend_boot.mapper.RoleMapper;
import com.yxw.live_vod_backend_boot.mapper.UserEmpMapper;
import com.yxw.live_vod_backend_boot.service.IUserService;
import com.yxw.live_vod_backend_boot.service.MenuService;
import com.yxw.live_vod_backend_boot.util.PageUtils;
import com.yxw.live_vod_backend_boot.util.UserUtil;
import com.yxw.live_vod_backend_boot.vo.RoleVO;
import com.yxw.live_vod_backend_boot.vo.UserEmpVO;
import com.yxw.live_vod_backend_boot.vo.YxCsMenuVo;
import com.yxw.yxnet_cd_center.common.dto.PageVO;
import com.yxw.yxnet_cd_center.common.exception.BaseException;
import com.yxw.yxnet_cd_center.common.utils.PasswordUtil;
import com.yxw.yxnet_cd_center.common.utils.PinyinUtill;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 员工管理Service业务层处理
 *
 * @author xiexuxin
 * @date 2023-09-19
 */
@Slf4j
@Service
public class UserEmpServiceImpl extends ServiceImpl<UserEmpMapper, YxCsUserEntity> implements IUserService {

    @Autowired
    private UserEmpMapper userMapper;

    @Autowired
    private RelevancyMapper relevancyMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuService menuService;

    @Autowired
    private UserUtil userUtil;

    @Autowired
    private DeptMapper deptMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addUser(UserEmpDTO empDTO) {
        log.info("开始处理【添加员工】的业务，参数：{}", empDTO);
        // 检查员工工号与员工电话是否已经存在
        LambdaQueryWrapper<YxCsUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(true, YxCsUserEntity::getUserNum, empDTO.getUserNum());
        Integer count = baseMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new BaseException("添加员工失败，尝试添加的员工工号重复！");
        }
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(true, YxCsUserEntity::getMobilePhone, empDTO.getMobilePhone());
        count = baseMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new BaseException("添加员工失败，尝试添加的员工电话重复！");
        }
        YxCsDeptEntity existingDept = deptMapper.selectById(empDTO.getDeptId());
        if (existingDept == null){
            throw new BaseException("未找到ID为【" + empDTO.getDeptId() + "】的所属部门");
        }
        // 创建员工实体对象，并将DTO对象的属性复制到实体对象中
        YxCsUserEntity empEntity = new YxCsUserEntity();
        BeanUtil.copyProperties(empDTO, empEntity);
        empEntity.setUserName(empDTO.getUserName());
        empEntity.setNickName(PinyinUtill.getPinYinHeadChar(empDTO.getUserName()));
        empEntity.setUserStatus(null == empEntity.getUserStatus() ? 1 : empEntity.getUserStatus());
        empEntity.setHireDate(new Date());
        empEntity.setCreateTime(LocalDateTime.now());
        // 插入员工信息
        int rows = userMapper.insert(empEntity);
        if (rows != 1) {
            throw new BaseException("添加员工失败，服务器忙，请稍后再尝试！");
        }
        Long id = empEntity.getId();
        updatePassword(id, empDTO.getPassword());
        // 获取员工角色ID列表
        Long[] roleIds = empDTO.getRoleIds();
        if (roleIds.length > 0){
            // 构建员工角色关联实体列表
            List<YxCsUserRoleEntity> userRoleList = new ArrayList<>();
            for (Long roleId : roleIds) {
                YxCsUserRoleEntity userRole = new YxCsUserRoleEntity();
                userRole.setUserId(empEntity.getId());
                userRole.setRoleId(roleId);
                userRoleList.add(userRole);
            }
            rows = relevancyMapper.insertUserRoleBatch(userRoleList);
            if (rows < 1) {
                throw new BaseException("关联员工角色失败，服务器忙，请稍后再尝试！");
            }
            // 获取员工角色对应的菜单权限
            List<YxCsUserMenuEntity> userMenuList = new ArrayList<>();
            YxCsUserMenuEntity userMenu = new YxCsUserMenuEntity();
            Set<Long> menuIdSet = new HashSet<>(); // 创建新的menuIdSet实例
            for (Long roleId : roleIds) {
                List<Long> menuIds = relevancyMapper.selectMenuIdsByRoleId(roleId);
                if (menuIds != null && !menuIds.isEmpty()) {
                    for (Long menuId : menuIds) {
                        addMenuAndParents(menuId, menuIdSet);
                    }
                }
            }
            if (menuIdSet.isEmpty()){
                return;
            }
            Long[] menuIdArray = menuIdSet.toArray(new Long[0]);
            userMenu.setUserId(empEntity.getId());
            userMenu.setMenuIds(menuIdArray); // 将菜单ID和父节点ID存入对象中
            userMenuList.add(userMenu);
            rows = relevancyMapper.insertUserMenus(userMenuList);
            if (rows < 1) {
                throw new BaseException("关联员工菜单失败，服务器忙，请稍后再尝试！");
            }
        }
    }

    // 查询菜单ID及其父节点ID的方法
    public Long selectParentIdByMenuId(Long menuId) {
        YxCsMenuEntity menu = menuService.selectMenuById(menuId);
        if (menu != null) {
            return menu.getParentId();
        }
        return null;
    }

    private void addMenuAndParents(Long menuId, Set<Long> menuIdSet) {
        Long parentId = selectParentIdByMenuId(menuId);
        if (parentId != null) {
            if (!menuIdSet.contains(parentId) && parentId != 0) {
                menuIdSet.add(parentId);
                addMenuAndParents(parentId, menuIdSet);
            }
        }
        if (!menuIdSet.contains(menuId) && menuId != 0) {
            menuIdSet.add(menuId);
        }
    }

    public void updatePassword(Long id,String password){
        String newPassword = PasswordUtil.signUserPassword(id,password);
        LambdaUpdateWrapper<YxCsUserEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(YxCsUserEntity::getUserId, id)
                .set(YxCsUserEntity::getPassword, newPassword);
        baseMapper.update(null, updateWrapper);
    }

    @Override
    public void deleteUserByIds(EmpDeleteDTO dto) {
        log.info("开始处理【删除员工】的业务，参数：{}", dto);
        if (dto != null && !dto.getIds().isEmpty()) {
            // 删除用户和角色的关联信息
            for (Long userId : dto.getIds()) {
                relevancyMapper.deleteUserRoleByUserId(userId);
                relevancyMapper.deleteUserMenuByUserId(userId);
            }
            // 批量删除用户信息
            int rows = userMapper.deleteUserByIds(dto.getIds());
            if (rows != dto.getIds().size()) {
                throw new BaseException("删除员工失败，服务器忙，请稍后再试！");
            }
        } else {
            throw new BaseException("删除员工失败，尝试删除的员工数据不存在！");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(UserEmpUpdateDTO empDTO) {
        log.info("开始处理【修改员工】的业务，参数：{}", empDTO);
        // 检查员工工号与员工电话是否已经存在
        LambdaQueryWrapper<YxCsUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(true, YxCsUserEntity::getUserNum, empDTO.getUserNum())
                    .ne(YxCsUserEntity::getId, empDTO.getId());
        Integer count = baseMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new BaseException("修改员工失败，尝试修改的员工工号重复！");
        }
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(true, YxCsUserEntity::getMobilePhone, empDTO.getMobilePhone())
                    .ne(YxCsUserEntity::getId, empDTO.getId());
        count = baseMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new BaseException("修改员工失败，尝试修改的员工电话重复！");
        }
        // 查询员工信息
        UserEmpVO queryResult = userMapper.selectUserById(empDTO.getId());
        if (queryResult == null || queryResult.getId() == 0) {
            throw new BaseException("修改员工失败，尝试修改的员工数据不存在！");
        }
        YxCsDeptEntity existingDept = deptMapper.selectById(empDTO.getDeptId());
        if (existingDept == null){
            throw new BaseException("未找到ID为【" + empDTO.getDeptId() + "】的所属部门");
        }
        // 将DTO转化为Entity，并更新员工信息
        YxCsUserEntity empEntity = new YxCsUserEntity();
        BeanUtils.copyProperties(empDTO, empEntity);
        empEntity.setId(empDTO.getId());
        empEntity.setGender(empDTO.getGender());
        empEntity.setUpdateTime(LocalDateTime.now());
        int rows = userMapper.updateById(empEntity);
        if (rows != 1) {
            throw new BaseException("修改员工失败，服务器忙，请稍后再试！");
        }
        // 获取员工角色ID列表
        Long[] roleIds = empDTO.getRoleIds();
        // 删除原有角色关联, 并插入新的角色关联
        relevancyMapper.deleteUserRoleByUserId(empDTO.getId());
        // 删除原有菜单关联, 并插入新的菜单关联
        relevancyMapper.deleteUserMenuByUserId(empDTO.getId());
        if (roleIds.length > 0) {
            List<YxCsUserRoleEntity> userRoleList = new ArrayList<>();
            for (Long id : roleIds) {
                YxCsUserRoleEntity userRole = new YxCsUserRoleEntity();
                userRole.setRoleId(id);
                userRole.setUserId(empDTO.getId());
                userRoleList.add(userRole);
            }
            rows = relevancyMapper.insertUserRoleBatch(userRoleList);
            if (rows < 1) {
                throw new BaseException("关联员工角色失败，服务器忙，请稍后再尝试！");
            }
            // 获取员工角色对应的菜单权限
            Set<Long> menuIdSet = new HashSet<>();
            for (Long roleId : roleIds) {
                List<Long> menuIds = relevancyMapper.selectMenuIdsByRoleId(roleId);
                if (menuIds != null && !menuIds.isEmpty()) {
                    for (Long menuId : menuIds) {
                        addMenuAndParents(menuId, menuIdSet);
                    }
                }
            }
            if (menuIdSet.isEmpty()) {
                return;
            }
            List<YxCsUserMenuEntity> userMenuList = new ArrayList<>();
            YxCsUserMenuEntity userMenu = new YxCsUserMenuEntity();
            userMenu.setUserId(empEntity.getId());
            userMenu.setMenuIds(menuIdSet.toArray(new Long[0]));
            userMenuList.add(userMenu);
            rows = relevancyMapper.insertUserMenus(userMenuList);
            if (rows < 1) {
                throw new BaseException("关联员工菜单失败，服务器忙，请稍后再尝试！");
            }
        }
    }

    @Override
    public void updateUserPicUrl(Long id, String picUrl) {
        LambdaUpdateWrapper<YxCsUserEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(YxCsUserEntity::getId, id)
                .set(YxCsUserEntity::getPicUrl, picUrl)
                .set(YxCsUserEntity::getUpdateTime, LocalDateTime.now());
        int rows = baseMapper.update(null, updateWrapper);
        if (rows != 1) {
            throw new BaseException("修改员工头像失败，服务器忙，请稍后再试！");
        }
    }

    @Override
    public UserEmpVO selectUserById(Long id) {
        log.info("开始处理【根据id查询员工】的业务，参数：{}", id);
        return userMapper.selectUserById(id);
    }

    @Override
    public PageVO<UserEmpVO> getUserList(UserEmpQueryDTO empQueryDTO) {
        log.info("开始处理【条件查询员工列表】的业务，条件参数：{}", empQueryDTO);
        Page<UserEmpVO> page = new Page<>(empQueryDTO.getCurrPage(), empQueryDTO.getPageSize());
        List<UserEmpVO> list = userMapper.getUserEmpList(page,empQueryDTO);
        return PageUtils.get(page, list);
    }

    @Override
    public List<UserEmpVO> userList() {
        log.info("开始处理【查询员工列表】的业务，无参数");
        return userMapper.getAll();
    }

    @Override
    public void updateUserMenuByUserId(List<YxCsUserMenuEntity> userMenus) {
        log.info("开始处理【员工编辑权限】的业务，参数：{}", userMenus);
        for (YxCsUserMenuEntity userMenu : userMenus) {
            Long userId = userMenu.getUserId();
            relevancyMapper.deleteUserMenuByUserId(userId);
        }
        // 如果roleMenus中的menuIds为空，则不执行后续处理逻辑
        if (userMenus.stream().anyMatch(roleMenu -> roleMenu.getMenuIds() == null || roleMenu.getMenuIds().length == 0)) {
            return;
        }
        // 构建新的角色菜单关联关系
        Set<Long> menuIdSet = new HashSet<>(); // 创建新的menuIdSet实例
        List<YxCsUserMenuEntity> newUserMenus = new ArrayList<>();
        for (YxCsUserMenuEntity userMenu : userMenus) {
            Long userId = userMenu.getUserId();
            Long[] menuIds = userMenu.getMenuIds();
            for (Long menuId : menuIds) {
                addMenuAndParents(menuId, menuIdSet);
            }
            Long[] menuIdArray = menuIdSet.toArray(new Long[0]);
            YxCsUserMenuEntity newUserMenu = new YxCsUserMenuEntity();
            newUserMenu.setUserId(userId);
            newUserMenu.setMenuIds(menuIdArray);
            newUserMenus.add(newUserMenu);
        }
        // 插入新的角色菜单关联关系
        relevancyMapper.insertUserMenus(newUserMenus);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean changePassword(PasswordDTO passwordDTO) {
        log.info("开始处理【修改密码】的业务，参数: {}", passwordDTO);
        // 根据用户ID查询用户信息
        YxCsUserEntity user = userMapper.selectById(passwordDTO.getId());
        if (user == null) {
            throw new BaseException("当前用戶不存在！");
        }
        // 验证当前密码是否正确
        if(!Objects.equals(PasswordUtil.signUserPassword(passwordDTO.getId(), passwordDTO.getCurrentPassword()), user.getPassword())) {
            throw new BaseException("当前密码不正确");
        }
        // 验证新密码和确认密码是否一致
        if(!Objects.equals(PasswordUtil.signUserPassword(passwordDTO.getId(), passwordDTO.getNewPassword()), PasswordUtil.signUserPassword(passwordDTO.getId(), passwordDTO.getConfirmPassword()))){
            throw new BaseException("新密码和确认密码不一致！");
        }
        // 更新密码和更新时间
        String newPassword = PasswordUtil.signUserPassword(passwordDTO.getId(), passwordDTO.getNewPassword());
        LambdaUpdateWrapper<YxCsUserEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(YxCsUserEntity::getUserId, passwordDTO.getId())
                .set(YxCsUserEntity::getPassword, newPassword)
                .set(YxCsUserEntity::getUpdateTime, LocalDateTime.now());
        int updateCount = baseMapper.update(null, updateWrapper);
        log.info("修改密码结果：{}", updateCount);
        return updateCount == 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean resetPasswords(ResetPasswordsDTO dto) {
        log.info("开始处理【重置密码】的业务，参数: {}", dto);
        if ("admin".equals(userUtil.getLoginUserVo().getUserName())) {
            // 根据用户ID查询用户信息
            YxCsUserEntity user = userMapper.selectById(dto.getId());
            if (user == null) {
                throw new BaseException("当前用戶不存在！");
            }
            // 验证新密码和确认密码是否一致
            if (!Objects.equals(PasswordUtil.signUserPassword(dto.getId(), dto.getNewPassword()), PasswordUtil.signUserPassword(dto.getId(), dto.getConfirmPassword()))) {
                throw new BaseException("新密码和确认密码不一致！");
            }
            // 更新密码和更新时间
            String newPassword = PasswordUtil.signUserPassword(dto.getId(), dto.getNewPassword());
            LambdaUpdateWrapper<YxCsUserEntity> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(YxCsUserEntity::getUserId, dto.getId())
                    .set(YxCsUserEntity::getPassword, newPassword)
                    .set(YxCsUserEntity::getUpdateTime, LocalDateTime.now());
            int updateCount = baseMapper.update(null, updateWrapper);
            log.info("修改密码结果：{}", updateCount);
            return updateCount == 1;
        }
        return null;
    }

    @Override
    public List<YxCsMenuVo> getMenuTreeByUser(Long userId) {
        List<YxCsUserMenuEntity> userMenu = relevancyMapper.selectUserMenuByUserId(userId);
        if (userMenu.isEmpty()){
           return null;
        }
        // 根据用户ID查询关联的菜单ID列表
        List<Long> menuIds = relevancyMapper.selectMenuIdsByUserId(userId).stream().distinct().collect(Collectors.toList());
        // 根据菜单ID列表查询菜单列表
        List<YxCsMenuEntity> menuList = userMapper.selectList(menuIds);
        List<YxCsMenuVo> menuVos = BeanUtil.copyToList(menuList, YxCsMenuVo.class);
        return buildMenuTree(menuVos, 0L);
    }

    @Override
    public List<YxCsMenuVo> getMenuTreeByUserMenu(Long userId) {
        List<RoleVO> roleList = roleMapper.selectRoleByUserId(userId);
        List<Long> roleIds = roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList());
        Set<Long> addedMenuIds = new HashSet<>(); // 保存已添加的菜单ID
        List<YxCsMenuVo> menuTree = new ArrayList<>();
        for (Long roleId : roleIds) {
            List<YxCsRoleMenuEntity> userRoleMenu = relevancyMapper.selectRoleMenuByRoleId(roleId);
            if (!userRoleMenu.isEmpty()) {
                // 根据角色ID查询关联的菜单ID列表
                List<Long> menuIds = relevancyMapper.selectMenuIdsByRoleId(roleId);
                List<YxCsMenuEntity> menuList = userMapper.selectList(menuIds);
                List<YxCsMenuVo> menuVos = BeanUtil.copyToList(menuList, YxCsMenuVo.class);
                // 构建菜单树
                List<YxCsMenuVo> roleMenuTree = buildMenuTree(menuVos, 0L);
                for (YxCsMenuVo menuVo : roleMenuTree) {
                    if (!addedMenuIds.contains(menuVo.getMenuId())) {
                        menuTree.add(menuVo);
                        addedMenuIds.add(menuVo.getMenuId());
                    }
                }
            }
        }
        return menuTree;
    }

    private List<YxCsMenuVo> buildMenuTree(List<YxCsMenuVo> menuVos, Long parentId) {
        List<YxCsMenuVo> tree = new ArrayList<>();
        for (YxCsMenuVo menuVo : menuVos) {
            if (parentId.equals(menuVo.getParentId())) {
                List<YxCsMenuVo> children = buildMenuTree(menuVos, menuVo.getMenuId());
                menuVo.setChildren(children);
                tree.add(menuVo);
            }
        }
        return tree;
    }

}
